package com.koron.device.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.BiMap;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.koron.bean.base.Constants;
import com.koron.bean.base.Response;
import com.koron.bean.query.PageQuery;
import com.koron.bean.standard.deviceClasssify.po.BrandStock;
import com.koron.bean.standard.deviceClasssify.po.Type;
import com.koron.bean.system.org.OrgBean;
import com.koron.bean.system.staff.po.AppUserPo;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.common.core.business.configsettings.utils.ConfigInfoTool;
import com.koron.common.core.business.datadict.utils.DataDictTool;
import com.koron.common.core.business.standard.feign.StandardFeignService;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.*;
import com.koron.common.core.util.qywx.QywxProperties;
import com.koron.common.core.util.weixin.WxProgramMessageUtil;
import com.koron.device.bean.*;
import com.koron.device.bean.bo.BaseImpData;
import com.koron.device.bean.bo.EqComposeBo;
import com.koron.device.bean.bo.TypeParamCompose;
import com.koron.device.bean.bo.TypeParamsJs;
import com.koron.device.bean.dto.LineEquipmentVo;
import com.koron.device.bean.po.EquipmentPo;
import com.koron.device.bean.query.AdvancedQuery;
import com.koron.device.bean.query.ERcodeQuery;
import com.koron.device.bean.query.EqParamQuery;
import com.koron.device.bean.template.EquipmentErrorMsg;
import com.koron.device.bean.template.EquipmentTemplate;
import com.koron.device.bean.template.ExportExcelMsg;
import com.koron.device.bean.vo.EquipmentCodeVO;
import com.koron.device.controller.ParamimpController;
import com.koron.device.enums.FloorEnum;
import com.koron.device.mapper.EquipmentLocationMapper;
import com.koron.device.mapper.EquipmentMapper;
import com.koron.device.mapper.SLanguagesConvertDao;
import com.koron.device.mapper.TypeParamsMapper;
import com.koron.device.service.*;
import com.koron.device.service.propconfig.DevicePropHandler;
import com.koron.device.utils.EqExportOrImpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.koron.ebs.mybatis.ADOConnection;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author qingfeng
 * @description: TODO
 * @date 2021/7/7 17:35
 */
@Slf4j
@Service
public class EquipmentServiceImpl implements EquipmentService {

    private EamUser getCurrUser() {
        return ThreadLocalContext.get();
    }

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private TypeParamsService typeParamsService;

    @Autowired
    private OrgCacheUtils orgCacheUtils;

    @Autowired
    private FeignService feignService;

    @Autowired
    private StandardFeignService standardFeign;

    @Autowired
    private DevicePropHandler propHandler;
    @Autowired
    private HttpServletRequest httpServletRequest;
    @Autowired
    private SLanguagesConvertService sLanguagesConvertService;
    @Autowired
    private SLanguagesConvertDao sLanguagesConvertDao;

    @Autowired
    EquipmentLocationService equipmentLocationService;

    private static final String rootId = "02000000000001";

    @Override
    @TaskAnnotation("insert")
    public Response insert(SessionFactory factory, Equipment equipment) {
        String language = httpServletRequest.getHeader("Language");
        // 实体节点必选分类
        if (StringUtils.isEmpty(equipment.getTypeId()) && "0".equals(equipment.getIsVirtual())) {
            return Response.fail("实体节点必选分类");
        }
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        if (StringUtils.isEmpty(equipment.getParentId())) {
            // 没有父级，说明是根节点
            equipment.setParentId(Constants.DEVICE_TREE_ROOT_CODE);
        }
        Equipment parent = mapper.getById(equipment.getParentId(),language);
        // 如果根节点不存在，则设置默认根节点
        if (Objects.isNull(parent)) {
            equipment.setParentName("0");
            equipment.setLevel(1);
            equipment.setFullPathCode(equipment.getId());
            equipment.setFullPathName(equipment.getName());
        } else {
            equipment.setParentName(parent.getName());
            // 父级level+1
            equipment.setLevel(parent.getLevel() + 1);
            equipment.setFullPathCode(parent.getFullPathCode() + "/" + equipment.getId());
            equipment.setFullPathName(parent.getFullPathName() + "/" + equipment.getName());
            // 父节点是层级是1（根节点） 且 新建节点是虚拟节点，设置节点为2
            if (parent.getFloor().equals("1") && equipment.getIsVirtual().equals("1")) {
                equipment.setFloor("2");
            }
            // 父节点是层级不是1（根节点） 且 新建节点是虚拟节点，层级等于父节点层级
            if (!parent.getFloor().equals("1") && equipment.getIsVirtual().equals("1")) {
                equipment.setFloor(parent.getFloor());
            }
        }

        if (equipment.getIsVirtual().equals("0") && equipment.getFloor().compareTo(parent.getFloor()) == -1) {
            return Response.fail("层级选择错误");
        }
        // 获取该层级的最大编码
        Integer maxLevelCode = mapper.getMaxLevelCodeByLevel(equipment.getLevel());
        maxLevelCode = maxLevelCode == null ? 1 : maxLevelCode + 1;
        equipment.setLevelCode(maxLevelCode);
        if ("0".equals(equipment.getParentId())) {
            equipment.setLevelPath(maxLevelCode + "");
        } else {
            String levelPath = mapper.getPathById(equipment.getParentId());
            equipment.setLevelPath(levelPath + "/" + maxLevelCode);
        }
        // 获取编码
        String code = getCode(mapper);
        if ("zsj".equals(ConfigInfoTool.getConfigByCode("system", "org").get("environment"))){
            String enCode = getKKS(mapper,equipment,equipment,equipment.getKksCode(),language);
            equipment.setEncode(enCode);
            equipment.setCode(code);
        }
        equipment.setCode(code);
        Collection<EquipmentParams> params = CollectionUtils.union(equipment.getBasicParams(), equipment.getTechParams());
        // 预设参数
        HashMap<String, String> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(params)) {
            params.forEach(item -> {
                item.setEquipmentId(equipment.getId());
                item.setId(CodeTools.getCode32());
                if (StringUtils.isEmpty(item.getParamResult())) {
                    item.setParamResult(item.getParamValue());
                }
            });
            mapper.batchInsertParams(new ArrayList<>(params));

            // 从所有参数中过滤出预设参数
            List<EquipmentParams> inadlist = params.stream().filter(p -> StrUtil.isNotBlank(p.getParamCode())).collect(Collectors.toList());
            for (EquipmentParams equipmentParams : inadlist) {
                map.put(equipmentParams.getParamCode(), equipmentParams.getParamResult());
            }
        }
        String beanToJson = FastJsonUtils.getBeanToJson(map);
        if (StrUtil.isNotBlank(beanToJson)) {
            equipment.setInAdvanceParam(beanToJson);
        }
        mapper.insert(equipment);

        // 如果是设备级、部件级 则 冗余
//        if(equipment.getFloor() != null && StrUtil.equalsAny(equipment.getFloor(), "5", "6")) {
//            try {
//                createMiniProgramQRCode(equipment.getId(), equipment.getName(), "release");
//            } catch (Exception e) {
//                log.error("新增设备、部件级，冗余台账二维码异常");
//                log.error(e.getMessage());
//            }
//        }
        sLanguagesConvertService.addBycreatEquip(equipment.getId(),equipment.getName());
        return Response.success(equipment.getId());
    }

    private synchronized String getCode(EquipmentMapper mapper) {
        String dateStr = DateFormatUtils.format(new Date(), "yyyyMMdd");
        String prefix = "E" + dateStr;
        String str = mapper.queryMaxCode(prefix);
        Integer num;
        if (StringUtils.isEmpty(str)) {
            num = 1;
        } else {
            num = Integer.valueOf(str) + 1;
        }
        return prefix + String.format("%03d", num);
    }

    @Override
    @TaskAnnotation("update")
    public Response update(SessionFactory factory, Equipment equipment) {
        String language = httpServletRequest.getHeader("Language");
        // 实体节点必选分类
        if (StringUtils.isEmpty(equipment.getTypeId()) && "0".equals(equipment.getIsVirtual())) {
            return Response.fail("实体节点必选分类");
        }
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        if(StrUtil.isNotBlank(equipment.getAmdCode())) {
            Equipment repeatEq = mapper.queryByAmdCodeAndId(equipment.getAmdCode(), equipment.getId(), equipment.getLocCode());
            cn.hutool.core.lang.Assert.isFalse(repeatEq != null, "编码重复");
//            Assert.isTrue(repeatEq == null, "编码重复");
        }
        // 数据库未更新时的设备信息
        Equipment origin = mapper.getById(equipment.getId(),language);
        if (!StringUtils.equals(equipment.getParentId(), "0")) {
            Equipment parent = mapper.getById(equipment.getParentId(),language);
            if (equipment.getFloor().compareTo(parent.getFloor()) == -1) {
                return Response.fail("层级选择错误");
            }
        }

        // 是否主体
        if(equipment.getIsmain() != null && equipment.getIsmain() == 1) {
            String fullPathCode = equipment.getFullPathCode();
            List<Equipment> list = mapper.queryByIdIn(StrUtil.split(fullPathCode, "/"));
            Optional<Equipment> exist = list.stream().filter(e -> e.getIsmain() != null && e.getIsmain() == 1).findFirst();
            if (exist.isPresent()) {
                cn.hutool.core.lang.Assert.isFalse(!exist.get().getId().equals(equipment.getId()),
                        StrUtil.format("{} 已经是主体", exist.get().getName()));
            }
            cn.hutool.core.lang.Assert.isFalse(StrUtil.isBlank(equipment.getLocCode()), "主体位置编码不能未空");
        }

        // 更新当前节点的所有子节点的parent_name
        mapper.updateParentName(equipment.getId(), equipment.getName());
        if (!StringUtils.equals(origin.getName(), equipment.getName())) {
            // 如果名字更新，则更新full_path_name
            mapper.updateFullPathName(origin.getName(), equipment.getName(), equipment.getId());
        }
        // 删除所有的参数（基础参数和技术参数），再重新插入
        mapper.deleteParams(equipment.getId());
        Collection<EquipmentParams> params = CollectionUtils.union(equipment.getBasicParams(), equipment.getTechParams());

        // 预设参数
        HashMap<String, String> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(params) && "0".equals(equipment.getIsVirtual())) {
            params.forEach(item -> {
                item.setEquipmentId(equipment.getId());
                item.setId(CodeTools.getCode32());
                if (StringUtils.isEmpty(item.getParamResult())) {
                    item.setParamResult(item.getParamValue());
                }
            });
            mapper.batchInsertParams(new ArrayList<>(params));

            // 从所有参数中过滤出预设参数
            List<EquipmentParams> inadlist = params.stream().filter(p -> StrUtil.isNotBlank(p.getParamCode())).collect(Collectors.toList());
            for (EquipmentParams equipmentParams : inadlist) {
                map.put(equipmentParams.getParamCode(), equipmentParams.getParamResult());
            }
        }
        String beanToJson = FastJsonUtils.getBeanToJson(map);
        if (StrUtil.isNotBlank(beanToJson)) {
            equipment.setInAdvanceParam(beanToJson);
        }
        mapper.update(equipment);
        return Response.success();
    }

    @Override
    @TaskAnnotation("delete")
    public Response delete(SessionFactory factory, String id) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        if (mapper.countChild(id) > 0) {
            return Response.fail("该节点下还有子节点，不能删除");
        }
        mapper.delete(id);
        return Response.success();
    }

    @Override
    @TaskAnnotation("getById")
    public Response<Equipment> getById(SessionFactory factory, String id, String code, String encode) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        Assert.isTrue(!StringUtils.isAllEmpty(id, code), "id和code不能同时为空");
        Equipment equipment = null;
        String language = httpServletRequest.getHeader("Language");
        if (StringUtils.isNotBlank(id)) {
            equipment = mapper.getById(id,language);
        } else if (StringUtils.isNotBlank(code)){
            equipment = mapper.getByCode(code,language);
        } else {
            equipment = mapper.getByEncode(encode,language);
        }
        Assert.notNull(equipment, "设备不存在");
        equipment.setDeptName(orgCacheUtils.getOrgNameById(equipment.getDeptId()));
        // 获取参数列表
        List<EquipmentParams> basicParams = ADOConnection.runTask(typeParamsService, "getBasicParamsByTypeId", List.class, equipment.getTypeId());
        equipment.setBasicParams(basicParams);
        List<EquipmentParams> techParams = ADOConnection.runTask(typeParamsService, "getTechParamsByTypeId", List.class, equipment.getTypeId());
        equipment.setTechParams(techParams);
        Collection<EquipmentParams> params = CollectionUtils.union(equipment.getBasicParams(), equipment.getTechParams());
        List<Map<String, String>> valueMap = mapper.getParams(id);
        // 设置参数值
        params.forEach(item -> {
            valueMap.forEach(item1 -> {
                if (item1.get("paramId").equals(item.getParamId())) {
                    item.setParamValue(item1.get("paramValue"));
                    item.setParamResult(item1.get("paramResult"));
                }
            });
        });
        return Response.success(equipment);
    }

    @Override
    @TaskAnnotation("getTree")
    public Response getTree(SessionFactory factory) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        List<Equipment> list = mapper.list(null, null,httpServletRequest.getHeader("Language"));
        list.stream().forEach(row -> row.setDeptName(orgCacheUtils.getOrgNameById(row.getDeptId())));
        Map<String, List<Equipment>> parentMap = list.stream().collect(Collectors.groupingBy(Equipment::getParentId));
        for (String key : parentMap.keySet()) {
            //获取parentId为key的数据
            List<Equipment> l = parentMap.get(key);
            //为children赋值
            for (Equipment t : l) {
                t.setChildren(parentMap.get(t.getId()));
            }
        }
        //根据根节点parentId获取整个树
        List<Equipment> result = parentMap.get("0");
        return Response.success(result);
    }

    @Override
    @TaskAnnotation("getTreeLazy")
    public Response getTreeLazy(SessionFactory factory, EquipmentQuery query) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        if (StringUtils.isEmpty(query.getParentId())) {
            query.setParentId(rootId);
        }
        List<Equipment> list = mapper.list(query.getParentId(), null,httpServletRequest.getHeader("Language"));
        Map<String, String> map = ConfigInfoTool.getConfigByCode("common", "tempConfig");
        if (MapUtil.isNotEmpty(map)) {
            if ("香港".equals(map.get("currentTenant"))) {
                list.stream().forEach(l -> {
                    String prefixStr = StrUtil.isNotBlank(l.getAmdCode()) ? l.getAmdCode() : l.getCode();
                    l.setName(StrUtil.join(" - ", prefixStr, l.getName()));
                });
            }
        }
        propHandler.setUp(factory, list, query);
        return Response.succ(list);
    }

    @Override
    @TaskAnnotation("getByViewType")
    public List<Equipment> getByViewType(SessionFactory factory, EquipmentQuery query) {
        String viewType = query.getViewType();
        String locCode = query.getLocCode();
        String subProcessCode = query.getSubProcessCode();
        String assetGroupCode = query.getAssetGroupCode();
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        cn.hutool.core.lang.Assert.isFalse(StrUtil.isBlank(viewType), "展示类型不能为空");
        cn.hutool.core.lang.Assert.isFalse(viewType.equals("locCode") && StrUtil.isBlank(locCode), "位置编码不能为空");
        cn.hutool.core.lang.Assert.isFalse(viewType.equals("subProcessCode") && StrUtil.isBlank(subProcessCode), "工艺编码不能为空");
        cn.hutool.core.lang.Assert.isFalse(viewType.equals("assetGroupCode") && StrUtil.isBlank(assetGroupCode), "专业编码不能为空");

        List<Equipment> list = new ArrayList();
        // 查工艺
        if (viewType.equals("locCode")) {
            List<String> subprocesscodelist = mapper.queryByLocCode(locCode);
            Equipment topOneLoccode = mapper.queryByLocCodeAndIsMain(locCode, 1);
            List<Map> qtylist = mapper.querySubProcessCodeChildrenQty(locCode, subprocesscodelist);
            Map<String, Long> childrenMap = qtylist.stream().collect(Collectors.toMap(map -> (String)map.get("subProcessCode"), map -> (long)map.get("qty")));
            for (String processCode : subprocesscodelist) {
                Equipment equipment = new Equipment();
                equipment.setId(StrUtil.join("",locCode, processCode));
                equipment.setParentId(topOneLoccode.getId());
                equipment.setIsVirtual("1");
                equipment.setLocCode(locCode);
                equipment.setSubProcessCode(processCode);
                equipment.setName(processCode);
                equipment.setSoViewType("subProcessCode");
                equipment.setChildrenNum(childrenMap.get(processCode).intValue());  //子级数量
                list.add(equipment);
            }
        }
        // 查专业
        if (viewType.equals("subProcessCode")) {
            List<String> assetgroupcodelist = mapper.queryByLocCodeAndSubProcessCode(locCode, subProcessCode);
            List<Map> qtylist = mapper.querySubProcessCodeAndassetGroupCodeChildrenQty(locCode, subProcessCode,assetgroupcodelist);
            Map<String, Long> childrenMap = qtylist.stream().collect(Collectors.toMap(map -> (String)map.get("assetGroupCode"), map -> (long)map.get("qty")));
            for (String assetgroupcode : assetgroupcodelist) {
                Equipment equipment = new Equipment();
                equipment.setId(StrUtil.join("",query.getId(),assetgroupcode));
                equipment.setParentId(query.getId());
                equipment.setIsVirtual("1");
                equipment.setLocCode(locCode);
                equipment.setSubProcessCode(subProcessCode);
                equipment.setAssetGroupCode(assetGroupCode);
                equipment.setName(assetgroupcode);
                equipment.setSoViewType("assetGroupCode");
                equipment.setChildrenNum(childrenMap.get(assetgroupcode).intValue());  // 子级数量
                list.add(equipment);
            }
        }
        // 查设备
        if (viewType.equals("assetGroupCode")) {
            list = mapper.queryByLocCodeAndSubProcessCodeAndAssetGroupCode(locCode, subProcessCode, assetGroupCode);
            Map<String, String> map = ConfigInfoTool.getConfigByCode("common", "tempConfig");
            if (MapUtil.isNotEmpty(map)) {
                if ("香港".equals(map.get("currentTenant"))) {
                    list.stream().forEach(l -> {
                        String prefixStr = StrUtil.isNotBlank(l.getAmdCode()) ? l.getAmdCode() : l.getCode();
                        l.setName(StrUtil.join(" - ", prefixStr, l.getName()));
                    });
                }
            }
            query.getConfigRules().add("hasChildren");
            propHandler.setUp(factory, list, query);
        }

        return list;
    }

    @Override
    @TaskAnnotation("robotGetTreeLazy")
    public Response robotGetTreeLazy(SessionFactory factory, String parentId) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        if (StringUtils.isEmpty(parentId)) {
            parentId = rootId;
        }
        List<EquipmentRobotDto> list = mapper.robotlist(parentId);
        return Response.succ(list);
    }

    @Override
    public Response getBasicParamsByTypeId(String typeId) {
        List<EquipmentParams> equipmentParams = ADOConnection.runTask(typeParamsService, "getBasicParamsByTypeId", List.class, typeId);
        return Response.success(equipmentParams);
    }

    @Override
    public Response getTechParamsByTypeId(String typeId) {
        List<EquipmentParams> equipmentParams = ADOConnection.runTask(typeParamsService, "getTechParamsByTypeId", List.class, typeId);
        return Response.success(equipmentParams);
    }

    @Override
    @TaskAnnotation("getParamById")
    public Response getParamById(SessionFactory factory, String paramId) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        return Response.ok(mapper.getParamById(paramId));
    }

    @Override
    public Map<String, List<EquipmentParams>> getParamsByTypeId(String typeId) {
        Map<String, List<EquipmentParams>> result = new HashMap<>();
        List<EquipmentParams> basicParams = ADOConnection.runTask(typeParamsService, "getBasicParamsByTypeId", List.class, typeId);
        List<EquipmentParams> techParams = ADOConnection.runTask(typeParamsService, "getTechParamsByTypeId", List.class, typeId);
        result.put("basic", basicParams);
        result.put("tech", techParams);
        return result;
    }

    @Override
    @TaskAnnotation("getGenericParams")
    public Map<String, Map<String, EquipmentParams>> getGenericParams(SessionFactory factory, List<String> equipmentIds) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        Map<String, Map<String, EquipmentParams>> map = new HashMap<>();
        // 获取默认的预设参数
        List<EquipmentParams> defaultPresetParams = ADOConnection.runTask(typeParamsService, "getDefaultParams", List.class);
        // name => code
        Map<String, String> defaultPresetParamMap = defaultPresetParams.stream().collect(Collectors.toMap(EquipmentParams::getParamName, EquipmentParams::getParamId));
        List<EquipmentParams> equipParams = mapper.getEquipParamsByEquipIds(equipmentIds);
        Map<String, List<EquipmentParams>> equipParamsMap = equipParams.stream().collect(Collectors.groupingBy(EquipmentParams::getEquipmentId));
        Iterator<Map.Entry<String, List<EquipmentParams>>> iterator = equipParamsMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map<String, EquipmentParams> equipMap = new HashMap<>();
            Map.Entry<String, List<EquipmentParams>> next = iterator.next();
            String equipmentId = next.getKey();
            List<EquipmentParams> presetParams = next.getValue();
            Map<String, EquipmentParams> presetParamMap = presetParams.stream()
                    .filter(row -> StringUtils.isNotBlank(row.getParamName()))
                    .collect(Collectors.toMap(EquipmentParams::getParamName, item -> item, (o1,o2) -> o1));
            defaultPresetParamMap.forEach((key, value) -> {
                if (!presetParamMap.containsKey(key)) {
                    return;
                }
                equipMap.put(value, presetParamMap.get(key));
            });
            map.put(equipmentId, equipMap);
        }
        return map;
    }

    @Override
    @TaskAnnotation("getGenericParam")
    public Map<String, EquipmentParams> getGenericParam(SessionFactory factory, String equipmentId) {
        return getGenericParams(factory, Arrays.asList(equipmentId)).get(equipmentId);
    }


    @Override
    @TaskAnnotation("getBatchBaseParams")
    public List<EquipmentParams> getBatchBaseParams(SessionFactory factory, List<String> equipmentIds) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        return mapper.getEquipParamsByEquipIds(equipmentIds);
    }

    /**
     * 1、子节点 ：id必填， targetId必填，sort为空，节点处于最后，即sort取最大值
     * 2、上方：id必填，targetId必填，但此时targetId为兄弟节点id, sort必填，id=targetId和sort比节点id=targetId大的节点，统一往后移，即sort+1
     * 3、下方：id必填，targetId必填，但此时targetId为兄弟节点id, sort必填，sort比节点id=targetId大的节点，统一往前移，即sort+1
     *
     * @param factory  会话
     * @param id       被移动的节点id
     * @param targetId 目前节点id
     * @param sort     在兄弟节点中的位置
     * @return
     */
    @Override
    @TaskAnnotation("moveNode")
    public Response moveNode(SessionFactory factory, String id, String targetId, Integer sort) {
        String language = httpServletRequest.getHeader("Language");
        // 移动完成后，当前节点和目标节点的关系， brotherId不为空，则为兄弟，parentId不为空，则为父子
        String brotherId = null, parentId = null;
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        Equipment equipment = mapper.getById(id,language);
        // 为移动前节点的full_path_name、full_path_code
        String originFullPathName = equipment.getFullPathName();
        String originFullPathCode = equipment.getFullPathCode();
        // 当前移动节点的层级x
        String floor = getById(factory, id, null,null).getData().getFloor();
        Equipment brother = null, parent = null;
        if (StringUtils.isEmpty(targetId)) {
            targetId = "0";
        }
        if (sort == null) {
            // 目标是父节点，只能操作层级，位置放在最后
            parentId = targetId;
            parent = mapper.getById(parentId,language);
        } else {
            // 目标是兄弟节点, 既能操作位置，也可操作层级
            brotherId = targetId;
            brother = mapper.getById(brotherId,language);
            parent = mapper.getById(brother.getParentId(),language);
        }
        Assert.notNull(parent, "父节点不存在");
        if (parent.getFloor().compareTo(floor) > 0) {
            return Response.fail("不允许移动至该节点下");
        }
        // 调整层级：parentId、parentName、levelPath、 level、full_path_code、full_path_name
        // 调整位置：levelCode、levelPath、sort
        if (StringUtils.isNotBlank(brotherId)) {
            equipment.setParentId(parent.getId());
            equipment.setParentName(parent.getName());
            equipment.setLevel(parent.getLevel() + 1);
            // 如果sort > 目标节点的sort，则为下方: sort + 1 ，反之上方: sort
            Integer levelCode = sort > brother.getLevelCode() ? brother.getLevelCode() + 1 : brother.getLevelCode();
            equipment.setLevelCode(levelCode);
            equipment.setLevelPath(parent.getLevelPath() + "/" + levelCode);
            equipment.setSort(levelCode);
            List<Equipment> children = mapper.getChildByParentId(parent.getId());
            Optional<Equipment> sameEquip = children.stream().filter(equip -> StringUtils.equals(equip.getId(), equipment.getId())).findFirst();
            //children.add(levelCode - 1, equipment);
            children.add(children.size()-1, equipment);
            if (sameEquip.isPresent()) {
                children.remove(sameEquip.get());
            }
            String parentLevelPath = parent.getLevelPath();
            // 重新调整目标兄弟树的参数
            Stream.iterate(0, i -> i + 1).limit(children.size()).forEach(i -> {
                Equipment child = children.get(i);
                child.setLevelCode(i + 1);
                child.setLevelPath(parentLevelPath + "/" + (i + 1));
                child.setSort(i + 1);
                mapper.update(child);
            });

            // 递归矫正节点下所有LevelPath(功能正常，响应太慢注释)
//            recursionCorrectLevelPath(mapper, parent);
        }

        // 移动到目标节点的子节点-执行
        if (StringUtils.isNotBlank(parentId)) {
            equipment.setParentId(parent.getId());
            equipment.setParentName(parent.getName());
            equipment.setLevel(parent.getLevel() + 1);
            equipment.setFullPathCode(parent.getFullPathCode() + "/" + equipment.getId());
            equipment.setFullPathName(parent.getFullPathName() + "/" + equipment.getName());
            Integer maxSort = mapper.getMaxSortByParentId(parentId);
            maxSort = maxSort == null ? 0 : maxSort;
            equipment.setLevelCode(maxSort + 1);
            equipment.setLevelPath(parent.getLevelPath() + "/" + equipment.getLevelCode());
            equipment.setSort(maxSort + 1);
            mapper.update(equipment);

            // 递归矫正节点下所有LevelPath(功能正常，响应太慢注释)
//            recursionCorrectLevelPath(mapper, equipment);
        }

        // 被调整的兄弟树
        List<Equipment> children = mapper.getChildByParentId(id);
        String parentLevelPath = parent.getLevelPath();
        // 重新设置兄弟树的参数
        Stream.iterate(0, i -> i + 1).limit(children.size()).forEach(i -> {
            Equipment child = children.get(i);
            child.setLevelCode(i + 1);
            child.setLevelPath(parentLevelPath + "/" + (i + 1));
            child.setSort(i + 1);
            mapper.update(child);
        });
        if (!StringUtils.equals(originFullPathCode, equipment.getFullPathName())) {
            mapper.updateFullPathName(originFullPathName, equipment.getFullPathName(), equipment.getId());
            mapper.updateFullPathCode(originFullPathCode, equipment.getFullPathCode(), equipment.getId());
        }
        return Response.success();
    }

    @Override
    @TaskAnnotation("batchMoveNode")
    public Response batchMoveNode(SessionFactory factory, List<String> movelist, String targetId, Integer sort) {

        String language = httpServletRequest.getHeader("Language");
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);

        // 目标节点
        Equipment tagetEq = mapper.getById(targetId, language);

        // 被移动节点
        List<Equipment> moveEqlist = mapper.getEquipsById(movelist);

        for (String modelId : movelist) {
            cn.hutool.core.lang.Assert.isFalse(StrUtil.split(tagetEq.getFullPathCode(), "/").contains(modelId), "不能移动到自身子级下");
        }

        // 父级节点
        Equipment parentIdEq = null;

        Integer moveSort = null;
        if(sort != null) {
            // 移动节点 与 确定了顺序
            parentIdEq = mapper.getById(tagetEq.getParentId(), language);
        } else {
            // 移动节点 顺序按子节点最大的算
            parentIdEq = tagetEq;
            mapper.getMaxSortByParentId(tagetEq.getParentId());
            moveSort = moveSort == null ? 0 : moveSort;
        }

        // 当前父级所有孩子节点
        List<Equipment> children = mapper.getChildByParentId(parentIdEq.getId());

        Integer minLevel = moveEqlist.stream().map(Equipment::getLevel).min(Comparator.comparing(x -> x)).orElse(null);
        cn.hutool.core.lang.Assert.isFalse(parentIdEq.getLevel().compareTo(minLevel) > 0, "移动设备层级不能比目标设备层级大");

        String fullPathCode = parentIdEq.getFullPathCode();
        String fullPathName = parentIdEq.getFullPathName();

        List<String> fullPathCodes = moveEqlist.stream().map(Equipment::getFullPathCode).collect(Collectors.toList());

        List<Equipment> alllist = mapper.batchqueryByFullPathCodeLike(fullPathCodes);

        List<Equipment> updatelist = new ArrayList<>();
        for (Equipment moveNode : moveEqlist) {
            String oldeqFullPathCode = moveNode.getFullPathCode();
            String oldeqFullPathName = moveNode.getFullPathName();
            for (Equipment equipment : alllist) {
                String fullPathCodeItem = equipment.getFullPathCode();
                String fullPathCodereplace = StrUtil.replace(fullPathCodeItem, oldeqFullPathCode, "");
                String fullPathNameItem = equipment.getFullPathName();
                String fullPathNamereplace = StrUtil.replace(fullPathNameItem, oldeqFullPathName, "");
                if (fullPathCodeItem.contains(oldeqFullPathCode)) {
                    equipment.setFullPathCode(StrUtil.format("{}/{}{}",fullPathCode,moveNode.getId(), fullPathCodereplace));
                    equipment.setFullPathName(StrUtil.format("{}/{}{}",fullPathName,moveNode.getName(), fullPathNamereplace));

                    if (fullPathCodeItem.equals(oldeqFullPathCode)) {
                        equipment.setParentId(parentIdEq.getId());
                        equipment.setParentName(parentIdEq.getName());
                        // 只处理了已移动节点，移动节点的字节的子节点需要依靠定时任务处理(不及时处理，未发现有功能受影响)
                        equipment.setLevelPath(parentIdEq.getLevelPath() + "/" + equipment.getLevelCode());
                    }
                } else {
                    continue;
                }
                Equipment bean = new Equipment();
                bean.setId(equipment.getId());
                bean.setParentId(equipment.getParentId());
                bean.setParentName(equipment.getParentName());
                bean.setFullPathCode(equipment.getFullPathCode());
                bean.setFullPathName(equipment.getFullPathName());
                updatelist.add(bean);
            }
        }

        Lists.partition(updatelist, 300).stream().forEach(p->{
            mapper.updateBatchSelective(p);
        });

        children.removeIf(e-> movelist.contains(e.getId()));

        if (sort != null) {
            for (int i = 0; i < children.size(); i++) {
                if (children.get(i).getId().equals(targetId)) {
                    moveSort = sort > tagetEq.getLevelCode() ? i + 1 : i;
                }
            }
        } else {
            moveSort = children.size();
        }

        // 目标节点下标连续循环增加移动设备
        for (int i = 0; i < moveEqlist.size(); i++) {
            Equipment bean = new Equipment();
            bean.setId(moveEqlist.get(i).getId());
            bean.setName(moveEqlist.get(i).getName());
            children.add(moveSort + i, bean);
        }

        String parentLevelPath = parentIdEq.getLevelPath();
        // 重新调整目标兄弟树的参数
        Stream.iterate(0, i -> i + 1).limit(children.size()).forEach(i -> {
            Equipment child = children.get(i);
            child.setLevelCode(i + 1);
            child.setLevelPath(parentLevelPath + "/" + (i + 1));
            child.setSort(i + 1);
            mapper.update(child);
        });

        return Response.ok();
    }

    @Override
    @TaskAnnotation("drag")
    public Response drag(SessionFactory factory, String dragId, String targetId, String position) {

        String language = httpServletRequest.getHeader("Language");
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);

        List<Equipment> list = mapper.queryByIdIn(CollUtil.newArrayList(dragId, targetId));
        cn.hutool.core.lang.Assert.isTrue(StrUtil.equals(list.get(0).getParentId(),list.get(1).getParentId()), "只能同级拖拽排序");

        Equipment dragEq = list.stream().filter(f -> f.getId().equals(dragId)).findFirst().get();
        Equipment targetEq =  list.stream().filter(f -> f.getId().equals(targetId)).findFirst().get();

        // 父级id
        Equipment parentEq = mapper.getById(targetEq.getParentId(), language);

        // 所有孩子节点
        List<Equipment> childlist = mapper.getChildByParentId(targetEq.getParentId());

        // 孩子节点中移除拖拽节点
        childlist.removeIf(e-> dragId.equals(e.getId()));

        Integer moveSort = null;
        for (int i = 0; i < childlist.size(); i++) {
            if (childlist.get(i).getId().equals(targetId)) {
                moveSort = i;
            }
        }
//        if(StrUtil.equals("before", position)) {
//            moveSort = moveSort;
//        }
        if(StrUtil.equals("after", position)) {
            moveSort = moveSort + 1;
        }

        childlist.add(moveSort, dragEq);

        String parentLevelPath = parentEq.getLevelPath();
        // 重新调整目标兄弟树的参数
        Stream.iterate(0, i -> i + 1).limit(childlist.size()).forEach(i -> {
            Equipment child = childlist.get(i);
            child.setLevelCode(i + 1);
            child.setLevelPath(parentLevelPath + "/" + (i + 1));
            child.setSort(i + 1);
            mapper.update(child);
        });
        return Response.ok();
    }

    @Override
    @TaskAnnotation("dragView")
    public Response dragView(SessionFactory factory, String targetId) {

        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        String language = httpServletRequest.getHeader("Language");

        // 只需要返回三层
        Equipment eq = mapper.getById(targetId, language);
        Equipment parentEq = mapper.getById(eq.getParentId(), language);
        List<Equipment> list = mapper.queryByFullPathCodeRightLike(parentEq.getFullPathCode());

//        Equipment topEq = mapper.getById(topId, language);
//        if (split.size() <= 2) {
//            topId = split.get(0);
//        } else {
//            // 取目标节点的上级
//            topId = split.get(split.size()-2);
//        }
        TreeUtils<Equipment, String> tree = new TreeUtils<>(
                list, Equipment::getId,
                Equipment::getParentId,
                Equipment::setChildren);

        List<Equipment> build = tree.build();

        for (Equipment equipment : build) {
            for (Equipment child : equipment.getChildren()) {
                for (Equipment childChild : child.getChildren()) {
                    childChild.setChildren(null);
                }
            }
        }

        return Response.ok(build);
    }

    /**
     * 移动多个节点
     * @param factory
     * @param ids
     * @param parentId
     * @return
     */
    @Override
    @TaskAnnotation(value = "moveMoreNode")
    public Response moveMoreNode(SessionFactory factory, List<String> ids, String parentId) {
        Assert.notNull(parentId,"父节点id不能为空！");
        Assert.notEmpty(ids,"移动节点id不能为空！");
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        String language = httpServletRequest.getHeader("Language");
        // 获取到父节点设备信息
        Equipment parentEquipment = mapper.getById(parentId,language);

        Assert.notNull(parentEquipment, "父节点不存在");

        ExecutorService executors = Executors.newFixedThreadPool(5);


        // 获取到移动节点的设备信息
        List<Equipment> moveEquipment = mapper.getEquipsById(ids);
        if (CollectionUtils.isNotEmpty(moveEquipment)){
            moveEquipment.forEach(equipment -> {
                String floor = equipment.getFloor();
                if (parentEquipment.getFloor().compareTo(floor) > 0) {
                    throw new RuntimeException("不允许移动至该节点下");
                }
                String originFullPathName = equipment.getFullPathName();
                String originFullPathCode = equipment.getFullPathCode();

                equipment.setParentId(parentEquipment.getId());
                equipment.setParentName(parentEquipment.getName());
                equipment.setLevel(parentEquipment.getLevel() + 1);
                equipment.setFullPathCode(parentEquipment.getFullPathCode() + "/" + equipment.getId());
                equipment.setFullPathName(parentEquipment.getFullPathName() + "/" + equipment.getName());
                Integer maxSort = mapper.getMaxSortByParentId(parentId);
                maxSort = maxSort == null ? 0 : maxSort;
                equipment.setLevelCode(maxSort + 1);
                equipment.setLevelPath(parentEquipment.getLevelPath() + "/" + equipment.getLevelCode());
                equipment.setSort(maxSort + 1);
                // 后续可以修改为批量更新
                mapper.update(equipment);

                // 更新全路径
                mapper.updateFullPathName(originFullPathName, equipment.getFullPathName(), equipment.getId());
                mapper.updateFullPathCode(originFullPathCode, equipment.getFullPathCode(), equipment.getId());

                // 被调整的兄弟树
                CompletableFuture.runAsync(()->{
                    List<Equipment> children = mapper.getChildByParentId(equipment.getId());
                    String parentLevelPath = parentEquipment.getLevelPath();
                    // 重新设置兄弟树的参数
                    Stream.iterate(0, i -> i + 1).limit(children.size()).forEach(i -> {
                        Equipment child = children.get(i);
                        child.setLevelCode(i + 1);
                        child.setLevelPath(parentLevelPath + "/" + (i + 1));
                        child.setSort(i + 1);
                        mapper.update(child);
                    });

//
                },executors);
            });

        }
        return Response.success();
    }

    /**
     * 递归矫正节点下所有LevelPath
     * @param mapper
     * @param parent
     */
    private void recursionCorrectLevelPath(EquipmentMapper mapper, Equipment parent) {
        // 关于父节点所有递归子级
        List<Equipment> alllist = mapper.queryByFullPathCodeLike(parent.getId());

        // 矫正LevelPath集合
        List<Equipment> buildLevelPathlist = new ArrayList();

        // 递归矫正
        builLevelPath(alllist, buildLevelPathlist, parent);

        Lists.partition(buildLevelPathlist, 300).stream().forEach(p -> {
            mapper.updateLevelPathBatchSelective(p);
        });
    }

    /**
     * 矫正builLevel
     * @param list
     * @param buildtreelist
     * @param parent
     */
    public static void builLevelPath(List<Equipment> list, List<Equipment> buildtreelist, Equipment parent) {

        List<Equipment> filterlist = list.stream().filter(f -> f.getParentId().equals(parent.getId())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(filterlist)) {
            for (Equipment bean : filterlist) {
                bean.setLevelPath(StrUtil.format("{}/{}", parent.getLevelPath(), bean.getSort()));
                buildtreelist.add(bean);
                builLevelPath(list, buildtreelist, bean);
            }
        }
    }

    @Override
    @TaskAnnotation("getEquipmentByLocation")
    public List<Equipment> getEquipmentByLocation(SessionFactory factory, String locationId) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        List<Equipment> list = mapper.getEquipmentByLocation(locationId);
        return list;
    }

    @Override
    @TaskAnnotation("getFloor")
    public Response<List> getFloor(SessionFactory factory, String parentId, String id) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        String language = httpServletRequest.getHeader("Language");
        List<Select> selects = getSelects();
        // 当前id和父id都为空，说明是新增根节点，返回全部
        if (StringUtils.isAllEmpty(parentId, id)) {
            return Response.success(selects);
        }
        // 父级设备
        Equipment equipment = mapper.getById(parentId,language);
        // 当前id为空，父id不为空，说明是新增子节点
        if (StringUtils.isEmpty(id)) {
            selects.stream().forEach(select -> select.setDisabled(equipment.getFloor().compareTo(select.getValue()) > 0));
            return Response.succ(selects);
        }
        List<Equipment> children = mapper.list(id, null,httpServletRequest.getHeader("Language"));
        log.info(children.toString());
        String s = children.size() > 0 ? children.stream().filter(c -> c.getFloor() != null).map(Equipment::getFloor).min((x, y) -> x.compareTo(y)).get() : "0";
        selects.stream().forEach(select -> select.setDisabled((equipment != null && equipment.getFloor().compareTo(select.getValue()) > 0) || (!"0".equals(s) && s.compareTo(select.getValue()) < 0)));
        return Response.succ(selects);
    }

    @Override
    @TaskAnnotation("queryList")
    public List<Equipment> queryList(SessionFactory factory, EquipmentQuery query) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        List<Equipment> result = mapper.list(query.getParentId(), query.getName(),httpServletRequest.getHeader("Language"));
        if (query.getPage() > 0 && query.getPageSize() > 0) {
            propHandler.setUp(factory, result, query);
        }
        return result;
    }

    /**
     * 根据设备参数值精确查询
     *
     * @param factory     会话
     * @param paramResult 分类名称
     * @return
     */
    @Override
    @TaskAnnotation("getParamsByResult")
    public Response<List<Equipment>> getParamsByResult(SessionFactory factory, String paramResult) {
        if (StringUtils.isEmpty(paramResult)) {
            return Response.succ(Collections.emptyList());
        }
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        List<EquipmentParams> defaultParams = ADOConnection.runTask(typeParamsService, "getDefaultParams", List.class);
        Map<String, String> defaultParamMap = defaultParams.stream().collect(Collectors.toMap(EquipmentParams::getParamName, EquipmentParams::getParamId));
        List<String> params = Arrays.asList(StringUtils.split(paramResult, ","));
        List<EquipmentParams> result = mapper.getEquipParamsByResult(params);
        result.stream().forEach(param -> param.setBasicParamSourceId(defaultParamMap.get(param.getParamName())));
        Map<String, List<EquipmentParams>> paramMap = result.stream().collect(Collectors.groupingBy(EquipmentParams::getEquipmentId));
        // 批量查询设备详情
        List<Equipment> equips = mapper.getEquipsById(new ArrayList<>(paramMap.keySet()));
        equips.stream().forEach(row -> row.setParams(paramMap.get(row.getId())));
        return Response.succ(equips);
    }

    @Override
    @TaskAnnotation("getParentIds")
    public Response<List<String>> getParentIds(SessionFactory factory, String id) {
        List<String> list = new LinkedList<>();
        Equipment equipment = getById(factory, id, null,null).getData();
        while (!StringUtils.equals(equipment.getParentId(), "0")) {
            equipment = getById(factory, equipment.getParentId(), null,null).getData();
            list.add(0, equipment.getId());
        }
        return Response.succ(list);
    }

    /**
     * 获取同组织下，最左上的设备台账
     *
     * @param factory
     * @param deptId
     * @return
     */
    @Override
    @TaskAnnotation("getLeftUpperEquipmentByDeptId")
    public Response getLeftUpperEquipmentByDeptId(SessionFactory factory, String deptId, String managerUnit) {
        Equipment equipment = null;
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        if (StringUtils.isNotBlank(deptId)) {
            return Response.ok(mapper.getLeftUpperEquipment(deptId, null));
        }
        if (StringUtils.isNotBlank(managerUnit)) {
            int row = mapper.existsParamByResult(Arrays.asList(managerUnit));
            return Response.ok(row > 0 ? mapper.getEquipmentByParamResult(Arrays.asList(managerUnit)) : null);
        }
        if (StringUtils.isAllBlank(deptId, managerUnit)) {
            String orgId = ThreadLocalContext.get().getOrgId();
            OrgBean orgBean = CommonUtils.ok(feignService.querySingleOrg(orgId));
            Assert.notNull(orgBean, "用户所在组织不存在");
            equipment = mapper.getLeftUpperEquipment(orgBean.getId(), null);
            if (equipment != null) {
                return Response.ok(equipment);
            }
            String[] orgs = StringUtils.split(orgBean.getLevelPath(), "/");
            for (int i = orgs.length - 1; i >= 0; i--) {
                // 逐层向上查找，直到有设备，如果没有，则返回空
                orgBean = CommonUtils.ok(feignService.querySingleOrg(orgs[i]));
                equipment = mapper.getLeftUpperEquipment(orgBean.getId(), null);
                if (equipment != null) {
                    return Response.ok(equipment);
                }
            }
        }
        return Response.ok(equipment);
    }

    @Override
    @TaskAnnotation("getUpTreeById")
    public Equipment getUpTreeById(SessionFactory factory, String id) {
        String language = httpServletRequest.getHeader("Language");
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        Equipment child = mapper.getById(id,language);
        while (!StringUtils.equals(child.getParentId(), rootId)) {
            Equipment equipment = mapper.getById(child.getParentId(),language);
            equipment.setChildren(Collections.singletonList(child));
            equipment.setChildrenNum(1);
            child = equipment;
        }
        return child;
    }

    @Override
    @TaskAnnotation("getLineTreeLazy")
    public List<LineEquipmentVo> getLineTreeLazy(SessionFactory factory, EquipmentQuery query) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        if (StringUtils.isEmpty(query.getParentId())) {
            Map<String, String> config = ConfigInfoTool.getConfigByCode("equipment", "line_root_device");
            query.setParentId(config.get("id"));
            if (query.getHasLatlon() == null) {
                query.setHasLatlon(true);
            }
        }
        List<Equipment> list = mapper.list(query.getParentId(), null,httpServletRequest.getHeader("Language"));
        propHandler.setUp(factory, list, query);

        // 设置经纬度
        Map<String, Map<String, String>> lineLatlon = new HashMap<>();
        if (query.getHasLatlon() != null && query.getHasLatlon()) {
            List<String> equipmentIds = list.stream().map(Equipment::getId).collect(Collectors.toList());
            lineLatlon = getTowerParams(factory, equipmentIds);
        }
        Map<String, Map<String, String>> finalLineLatlon = lineLatlon;
        return list.stream().map(e -> {
            LineEquipmentVo lineEquipmentVo = BeanUtil.toBean(e, LineEquipmentVo.class);
            Map<String, String> map = finalLineLatlon.getOrDefault(e.getId(), null);
            if (map == null) {
                return lineEquipmentVo;
            }
            lineEquipmentVo.setLatitude(map.getOrDefault("latitude", null));
            lineEquipmentVo.setLongitude(map.getOrDefault("longitude", null));
            lineEquipmentVo.setDeptManager(map.getOrDefault("deptManager", null));
            lineEquipmentVo.setDeptManagerName(map.getOrDefault("deptManagerName", null));
            return lineEquipmentVo;
        }).collect(Collectors.toList());
    }

    @Override
    @TaskAnnotation("getTowerParams")
    public Map<String, Map<String, String>> getTowerParams(SessionFactory factory, List<String> equipmentIds) {
        if (CollectionUtils.isEmpty(equipmentIds)) {
            return null;
        }
        List<EquipmentParams> data = getBatchBaseParams(factory, equipmentIds);
        // equipmentId -> list<param> 拿到改设备的经纬度
        Map<String, List<EquipmentParams>> paramsMap = data.stream().filter(e -> StrUtil.equalsAny(e.getParamName(), "经度", "纬度", "管理部门")).collect(Collectors.groupingBy(EquipmentParams::getEquipmentId));
        Map<String, Map<String, String>> result = new HashMap<>();
        paramsMap.forEach((k,v) -> {
            Map<String, String> map = new HashMap<>();
           //设置一个不存在的经纬度值，判断是否存在经纬度
            double lat = 500;
            double lon = 500;
            for (EquipmentParams equipmentParams : v) {
                if ("经度".equals(equipmentParams.getParamName())) {
                    lon = NumberUtil.parseDouble(equipmentParams.getParamValue());
                    map.put("longitude", equipmentParams.getParamValue());
                } else if ("纬度".equals(equipmentParams.getParamName())) {
                    lat = NumberUtil.parseDouble(equipmentParams.getParamValue());
                    map.put("latitude", equipmentParams.getParamValue());
                } else if ("管理部门".equals(equipmentParams.getParamName())) {
                    map.put("deptManager", equipmentParams.getParamResult());
                    map.put("deptManagerName", equipmentParams.getParamValue());
                }
                //存在经纬度时将gps坐标转换为高德坐标
               if (lat!=500 && lon!=500){
                    double[] doubles = LatLonUtil.gps84_To_Gcj02(lat, lon);
                    map.put("longitude",String.valueOf(doubles[1]));
                    map.put("latitude",String.valueOf(doubles[0]));
                }
            }
            result.put(k, map);
        });
        return result;
    }

    @Override
    @TaskAnnotation("advancedQueryEquipment")
    public PageInfo<EquipmentPo> advancedQueryEquipment(SessionFactory factory, PageQuery pageQuery, AdvancedQuery query) {
        PageHelper.startPage(pageQuery.getPage(), pageQuery.getPageSize(), pageQuery.getOrderBy());
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        List<EquipmentPo> list = mapper.getByParamsList(query);
        return new PageInfo<>(list);
    }

    @Override
    @TaskAnnotation("export")
    public List<EquipmentExcel> export(SessionFactory factory, String equipmentId) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        String language = httpServletRequest.getHeader("Language");
        // 获取节点下的所有设备及其子设备(不含隐藏的根节点)
        List<Equipment> equipments = mapper.getChildrenById(equipmentId, false, 2);
        Equipment topNode = mapper.getById(equipmentId,language);
        Map<String, String> levelMap = DataDictTool.getDataDictByCode("equipmentAccount", "equipment_level");//设备层级
        Map<String, String> nodeTypeMap = DataDictTool.getDataDictByCode("equipmentAccount", "equipment_node_type");//节点类型
        List<String> typeIds = equipments.stream().map(Equipment::getTypeId).distinct().collect(Collectors.toList());
        List<Type> types = CommonUtils.ok(standardFeign.getRealByIds(typeIds));
        Map<String, Type> typeMap = types.stream().collect(Collectors.toMap(Type::getId, item -> item));
        List<EquipmentExcel> excels = new ArrayList<>();
//        List<EquipmentExcel> excels = equipments.stream().map(row -> {
//            EquipmentExcel excel = new EquipmentExcel();
//            excel.setName(row.getName());
//            excel.setId(row.getId());
//            String levelCode = StringUtils.replace(row.getLevelPath(), "/", ".");
//            // 将隐藏的跟节点替换成空（因为根节点，针对用户不可见）
//            excel.setLevelCode(levelCode.replaceFirst("1.", ""));
//            excel.setCode(row.getCode());
//            excel.setIsVirtual(nodeTypeMap.get(row.getIsVirtual()));
//            excel.setLevel(levelMap.get(row.getFloor()));
//            excel.setDeptId(orgCacheUtils.getOrgNameById(row.getDeptId()));
//            if (typeMap.containsKey(row.getTypeId())) {
//                Type type = typeMap.get(row.getTypeId());
//                excel.setTypeCode(type.getCode());
//                excel.setTypeName(type.getName());
////                excel.setTypeId(row.getTypeId());//临时
//            }
//            return excel;
//        }).sorted(Comparator.comparing(EquipmentExcel::getLevelCode)).collect(Collectors.toList());
        List<Equipment> collect = (List<Equipment>)equipments.stream().filter(o -> StringUtils.equals(equipmentId, o.getParentId())).peek(o -> o.setChildren(getChildList(o, equipments))).collect(Collectors.toList());
        topNode.setChildren(collect);
        List<Equipment> jsonToList = new ArrayList<>();
        jsonToList.add(topNode);
        /*List<Tree<String>> treeList = TreeUtil.build(equipments, topNode.getParentId(), new TreeNodeConfig(),
                (treeNode, node) -> {
                    node.setId(treeNode.getId());
                    node.setParentId(treeNode.getParentId());
                    // 如果不想一个个putExtra，可以直接Bean 转 Map 遍历赋值
                    Map<String, Object> map = BeanUtil.beanToMap(treeNode);
                    for (Map.Entry<String, Object> entry : map.entrySet()) {
                        node.putExtra(entry.getKey(), entry.getValue());
                    }
                });
        List<Equipment> jsonToList = FastJsonUtils.getJsonToList(FastJsonUtils.getBeanToJson(treeList), Equipment.class);*/

        //根节点生成序号
        for (int i = 0; i < jsonToList.size(); i++) {
            Equipment treeVO = jsonToList.get(i);
            String levelPath = i + 1 + "";
            treeVO.setLevelPath(levelPath);
            recursiveLoopCreateSeqNum(treeVO.getChildren(), levelPath);
        }

        recursionEq(jsonToList, excels, nodeTypeMap, levelMap, typeMap);

        EquipmentExcel header = new EquipmentExcel();
        header.setLevelCode("层级编号");
        header.setName("设备名称");
        header.setId("设备id");
        header.setCode("设备编号");
        header.setIsVirtual("节点类型");
        header.setLevel("所属层级");
        header.setTypeName("分类名称");
        header.setTypeCode("分类编码");
//        header.setTypeId("分类Id");
        header.setDeptId("关联组织");
        excels.add(0, header);
        return excels;
    }
    private List<Equipment> getChildList(Equipment equipment, List<Equipment> list) {
        return (List<Equipment>)list.stream()
                .filter(o -> StringUtils.equals(String.valueOf(equipment.getId()), o.getParentId()))
                .peek(o -> o.setChildren(getChildList(o, list)))
                .collect(Collectors.toList());
    }
    // 正序递归 实体
    public void recursionEq(List<Equipment> jsonToList, List<EquipmentExcel> excels,
                            Map<String, String> nodeTypeMap,  Map<String, String> levelMap, Map<String, Type> typeMap) {
        for (Equipment vo : jsonToList) {
            EquipmentExcel convert = Convert.convert(EquipmentExcel.class, vo);
            convert.setCode(StrUtil.isBlank(vo.getAmdCode()) ? vo.getCode() : vo.getAmdCode());  // 三目：amdCode不为空取amdCode, 为空取系统生成code
            convert.setLevelCode(vo.getLevelPath());
            convert.setIsVirtual(nodeTypeMap.get(vo.getIsVirtual()));
            convert.setLevel(levelMap.get(vo.getFloor()));
            convert.setDeptId(orgCacheUtils.getOrgNameById(vo.getDeptId()));
            if (typeMap.containsKey(vo.getTypeId())) {
                Type type = typeMap.get(vo.getTypeId());
                convert.setTypeCode(type.getCode());
                convert.setTypeName(type.getName());
            }
            excels.add(convert);
            if (CollUtil.isNotEmpty(vo.getChildren())) {
                recursionEq(vo.getChildren(), excels, nodeTypeMap, levelMap, typeMap);
            }
        }
    }

    void recursiveLoopCreateSeqNum(List<Equipment> treeList, String levelPath) {
        if (null == treeList || treeList.size() < 1) {
            return;
        }
        for (int i = 0; i < treeList.size(); i++) {
            Equipment treeVO = treeList.get(i);
            String childLevelPath = levelPath + "." + (i + 1);
            treeVO.setLevelPath(childLevelPath);
            recursiveLoopCreateSeqNum(treeVO.getChildren(), childLevelPath);
        }
    }

    /**
     * 获取所有层级下拉
     *
     * @return
     */
    private static List<Select> getSelects() {
        List<Select> list = Lists.newArrayList();
//        for (FloorEnum item : FloorEnum.values()) {
//            Select select = new Select();
//            select.setLabel(item.getLabel());
//            select.setValue(item.getValue());
//            select.setDisabled(false);
//            list.add(select);
//        }
        BiMap<String, String> majorMap = new BiMap<>(DataDictTool.getDataDictByCode("equipmentAccount", "equipment_level"));
        for (Map.Entry<String, String> entry : majorMap.entrySet()) {
            Select select = new Select();
            select.setLabel(entry.getValue());
            select.setValue(entry.getKey());
            select.setDisabled(false);
            list.add(select);
        }
        return list;
    }


    /**
     * 导入数据校验
     *
     * @param factory
     * @param importlist 导入数据
     * @param parenteq   父级节点
     * @param cTypePo    设备分类集合
     * @return
     */
    @TaskAnnotation("importEquipment")
    public List<EquipmentErrorMsg> importEquipment(SessionFactory factory, List<EquipmentTemplate> importlist, Equipment parenteq, CTypePo cTypePo) {

        Map<String, String> levelMap = DataDictTool.getDataDictByCode("equipmentAccount", "equipment_level");//设备层级
        Map<String, String> nodeTypeMap = DataDictTool.getDataDictByCode("equipmentAccount", "equipment_node_type");//节点类型

        Map<String, String> levelMapCo = levelMap.keySet().stream().collect(Collectors.toMap(x -> levelMap.get(x), x -> x));//键值交换
        Map<String, String> nodeTypeMapCo = nodeTypeMap.keySet().stream().collect(Collectors.toMap(x -> nodeTypeMap.get(x), x -> x));//键值交换
        //导入数据的数据来源id合集
//        List<String> Dslist = importlist.stream().map(EquipmentTemplate::getDataSourcesId).collect(Collectors.toList());
        // 导入数据的层级编码集合
        List<String> levelpathlist = importlist.stream().map(EquipmentTemplate::getLevelPath).collect(Collectors.toList());
        List<String> checkLevellist = levelpathlist.stream().filter(l -> StrUtil.isNotBlank(l)).collect(Collectors.toList());
        // 判断是否重复编号 (导入文件第一列 层级编号 筛选出重复的数据)
        checkLevellist = CommonUtils.getDuplicateElements(checkLevellist);
        cn.hutool.core.lang.Assert.isFalse(CollUtil.isNotEmpty(checkLevellist), StrUtil.format("存在重复编号{}", CollUtil.join(checkLevellist, ",")));

        Map<String, EquipmentTemplate> parent = importlist.stream().collect(Collectors.toMap(EquipmentTemplate::getLevelPath, item -> item, (x1, x2) -> x1));

        Boolean checkisError = false;
        List<EquipmentErrorMsg> errorlist = new ArrayList();
        for (EquipmentTemplate tele : importlist) {

            if (StrUtil.isBlank(tele.getName()) && StrUtil.isBlank(tele.getLevelPath())) {
                continue;
            }
//            if(StrUtil.isBlank(tele.getDataSourcesId()) && tele.getDataSourcesId().length() != 32){
//                errorlist.add(Convert.convert(EquipmentErrorMsg.class,tele).setErrorMsg("数据来源id不存在"));
//            }

            if (StrUtil.isBlank(levelMapCo.get(tele.getFloorStr()))) {
                errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele).setErrorMsg("设备业务层级不存在"));
                continue;
            }
            if (tele.getName().contains("/")) {
                errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele).setErrorMsg("设备名称含有/"));
                continue;
            }
            tele.setFloor(levelMapCo.get(tele.getFloorStr()));//业务层级赋值

            if (StrUtil.isBlank(nodeTypeMapCo.get(tele.getIsVirtualStr()))) {
                errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele).setErrorMsg("节点类型不存在"));
                continue;
            }
            tele.setIsVirtual(nodeTypeMapCo.get(tele.getIsVirtualStr()));//是否虚拟节点赋值

            if (tele.getTypeCode() != null && !cTypePo.getCtypecode().contains(tele.getTypeCode())) {
                errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele).setErrorMsg("设备分类编码不存在"));
                continue;
            }
            if (tele.getTypeName() != null && !cTypePo.getCtypename().contains(tele.getTypeName())) {
                errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele).setErrorMsg("设备分类名称不存在"));
                continue;
            }

            if (StrUtil.split(tele.getLevelPath(),".").size() > 1) {
                String parentLevelPath = tele.getLevelPath().substring(0, tele.getLevelPath().lastIndexOf("."));//根据层级编码，截取出父级编码
                if (!levelpathlist.contains(parentLevelPath)) {
                    errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele).setErrorMsg("找不到父级编码"));
                    continue;
                }
                if (parent.get(parentLevelPath).getFloor() == null) {
                    errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele).setErrorMsg("找不到父级业务层级，无法比较"));
                    continue;
                }
                Integer parentFloor = Integer.valueOf(parent.get(parentLevelPath).getFloor());//父级业务层级
                Integer childrenFloor = Integer.valueOf(tele.getFloor());//自身业务层级
                //父级业务层级 比 自己 要大 不允许
                if (parentFloor.compareTo(childrenFloor) > 0) {
                    errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele).setErrorMsg("业务层级不允许比上级小"));
                    continue;
                }
                tele.setParentLevelPath(parentLevelPath);
            } else {
                Integer parentFloor = Integer.valueOf(parenteq.getFloor());//父级业务层级
                Integer childrenFloor = Integer.valueOf(tele.getFloor());//自身业务层级
                //父级业务层级 比 自己 要大 不允许
                if (parentFloor.compareTo(childrenFloor) > 0) {
                    errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele).setErrorMsg("业务层级不允许比上级小"));
                    continue;
                }

            }

            errorlist.add(Convert.convert(EquipmentErrorMsg.class, tele));
        }
        return errorlist;
    }

    /**
     * 台账构建入库
     *
     * @param factory
     * @param checklist 表格导入数据
     * @param parentEq  父级节点
     * @return
     */
    @TaskAnnotation("buildEquipment")
    public void buildEquipment(SessionFactory factory, List<EquipmentErrorMsg> checklist, Equipment parentEq, CTypePo cTypePo) {
        Map<String, String> ctypemap = cTypePo.getTypeCodeIdmap();

        //导入数据转换成台账数据格式数据
        List<Equipment> equipmentlist = new ArrayList();
        for (EquipmentErrorMsg imp : checklist) {
            Equipment equipment = Convert.convert(Equipment.class, imp);
            equipment.setId(CodeTools.getCode32());
            equipment.setAmdCode(imp.getAmdCode());
            equipment.setEncode(imp.getEncode());
            equipment.setTypeId(ctypemap.get(imp.getTypeCode()));
            equipment.setCreateBy(getCurrUser().getAccount());
            equipment.setCreateByName(getCurrUser().getName());
            equipment.setCreateTime(new Date());
            equipment.setDeleteFlag(0);
            equipment.setStatus("1");
            equipment.setDataSources(StrUtil.format("{}导入", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm")));
//          equipment.setDataSources(imp.getDataSourcesId());
            String levelPath = StrUtil.trim(imp.getLevelPath());
            String sort = levelPath.substring(levelPath.lastIndexOf(".") + 1, levelPath.length());//导入的业务层级最后的数字决定台账顺序
            equipment.setSort(Integer.valueOf(sort));
            equipmentlist.add(equipment);
        }
        //根据带入的层级编码 和 生成id 组成map, 用匹配出自身的父级
        Map<String, String> levelPathmap = equipmentlist.stream().collect(Collectors.toMap(Equipment::getLevelPath, Equipment::getId));

        // 匹配父级
        for (Equipment equipment : equipmentlist) {
            if (StrUtil.split(equipment.getLevelPath(),".").size() > 1) {
                String parentLevelPath = equipment.getLevelPath().substring(0, equipment.getLevelPath().lastIndexOf("."));//根据层级编码，截取出父级编码
                equipment.setParentId(levelPathmap.get(parentLevelPath));
            } else {
                equipment.setParentId(parentEq.getId());
            }
        }
        equipmentlist.add(parentEq);

        String dateStr = DateFormatUtils.format(new Date(), "yyyy");
        String prefix = "E" + dateStr;
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        String str = mapper.impQueryMaxCode(prefix);
        if (StringUtils.isEmpty(str)) {
            code = 1;
        } else {
            code = Integer.valueOf(str) + 1;
        }

        JSONArray totalTree = listToTree(JSON.parseArray(JSON.toJSONString(equipmentlist)), "id", "parentId", "children");
        JSONArray tree = new JSONArray();
        Iterator<Object> totalTreeIterator = totalTree.stream().iterator();
        while (totalTreeIterator.hasNext()) { //删除垃圾数据，只留"父节点"
            JSONObject next = (JSONObject) totalTreeIterator.next();
            if (StringUtils.equals(next.getString("id"), parentEq.getId())) {
                tree.add(next);
            }
        }
        List<Equipment> treeVos = JSONArray.parseArray(JSONArray.toJSONString(tree), Equipment.class);
        List<Equipment> vos = new ArrayList<>();
        treeDeviceToList(treeVos, vos);
        Map<String, Equipment> typeMap = vos.stream().collect(Collectors.toMap(Equipment::getId, item -> item));
        typeMap.put(parentEq.getId(), parentEq);//补充父级id
        configDeviceLevel(mapper, treeVos, typeMap, parentEq);
        List<Equipment> list1 = deviceVoToBean(vos);

        list1.removeIf(e -> e.getId().equals(parentEq.getId()));//插入时候移除父节点id
        List<SLanguagesConvert> list = new ArrayList<>();
        Date date = new Date();
        Lists.partition(list1, 300).stream().forEach(p -> {
            p.stream().forEach(equipment -> {
                list.addAll(sLanguagesConvertService.buildSLanguagesConvert(equipment.getId(),equipment.getName(),date));
            });
            sLanguagesConvertDao.insertOrUpdateBatch(list);
            list.clear();
            mapper.batchInsert(p);
        });

        return;
    }


    private static List<Equipment> deviceVoToBean(List<Equipment> vos) {
        List<Equipment> equipments = new ArrayList<>();
        vos.stream().forEach(row -> {
            try {
                Equipment equipment = new Equipment();
                BeanUtils.copyProperties(row, equipment);
                equipments.add(equipment);
            } catch (Exception e) {
                log.error(e.getMessage(),e);
            }
        });
        return equipments;
    }

    private static void treeDeviceToList(List<Equipment> treeVos, List<Equipment> vos) {
        for (int i = 0; i < treeVos.size(); i++) {
            vos.add(treeVos.get(i));
            if (!CollectionUtils.isEmpty(treeVos.get(i).getChildren())) {
                treeDeviceToList(treeVos.get(i).getChildren(), vos);
            }
        }
    }

    public static JSONArray listToTree(JSONArray arr, String id, String pid, String child) {
        JSONArray r = new JSONArray();
        JSONObject hash = new JSONObject(new LinkedHashMap());
        for (int i = 0; i < arr.size(); i++) {
            JSONObject json = (JSONObject) arr.get(i);
            hash.put(json.getString(id), json);
        }
        for (int j = 0; j < arr.size(); j++) {
            JSONObject aVal = (JSONObject) arr.get(j);
            JSONObject hashVP = (JSONObject) hash.get(aVal.get(pid).toString());
            if (hashVP != null) {
                if (hashVP.get(child) != null) {
                    JSONArray ch = (JSONArray) hashVP.get(child);
                    ch.add(aVal);
                    hashVP.put(child, ch);
                } else {
                    JSONArray ch = new JSONArray();
                    ch.add(aVal);
                    hashVP.put(child, ch);
                }
            } else {
                r.add(aVal);
            }
        }
        return r;
    }

    public static int code;

    private static void configDeviceLevel(EquipmentMapper mapper, List<Equipment> vos, Map<String, Equipment> typeMap, Equipment parentEq) {
        Iterator<Equipment> iterator = vos.iterator();
        int k = 0;
        while (iterator.hasNext()) {
            Equipment vo = iterator.next();
            // 表格顶层节点 找父节点的已有子节点格数量
            if(parentEq.getId().equals(vo.getParentId())) {
                List<Equipment> list = mapper.getChildByParentId(parentEq.getId());
                // 子节点数等于null
                k = CollUtil.isEmpty(list) ? 0 : list.size();
            }
            if (!StringUtils.equals(vo.getParentId(), parentEq.getParentId())) {
                if (!typeMap.containsKey(vo.getParentId())) {
                    continue;
                }
                // 如果有父节点
                Equipment parent = typeMap.get(vo.getParentId());
                vo.setParentName(parent.getName());
                vo.setLevel(parent.getLevel() + 1);
                vo.setLevelPath(parent.getLevelPath() + "/" + (k + 1));
                vo.setFullPathName(parent.getFullPathName() + "/" + vo.getName());
                vo.setFullPathCode(parent.getFullPathCode() + "/" + vo.getId());
            } else {
                vo.setLevel(1);
                vo.setLevelPath(String.valueOf(k + 1));
                vo.setFullPathName(vo.getName());
                vo.setFullPathCode(vo.getId());
            }
            String dateStr = DateFormatUtils.format(new Date(), "yyyy");
            vo.setCode("E" + dateStr + String.format("%07d", code));
//            vo.setFloor("1");
            code++;
            k++; // TODO 位置？
            vo.setLevelCode(k);
            vo.setSort((k));
            if (!CollectionUtils.isEmpty(vo.getChildren())) {
                List<Equipment> children = vo.getChildren();
                Collections.sort(children, Comparator.comparingInt(Equipment::getSort));
                vo.setChildren(children);
                configDeviceLevel(mapper, vo.getChildren(), typeMap, parentEq);
            }
        }
    }

    private RestTemplate template = new RestTemplate();

    @Autowired
    private QywxProperties qywxProperties;

    @Autowired
    private WxProgramMessageUtil wxProgramUtil;


    public File createMiniProgramQRCode(String id, String name, String envVersion) {
        log.info("<---开始生成二维码--->");
        Map<String, Object> param = new HashMap<>();
        param.put("page", "pages/equiLedger/equiDetail");
        param.put("scene", id);
        param.put("check_path", true);
//        param.put("env_version", "trial");
        param.put("env_version", envVersion);
        // 请求路径url
        String token = wxProgramUtil.getAccessTokenCache();
        log.info("token = {}", token);
        String url = qywxProperties.getCodeUnLimit() + "?access_token=" + token;
        log.info("url = {}", url);
        // 请求体body
        HttpHeaders header = new HttpHeaders();
        header.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity requestEntity = new HttpEntity(param, header);
        ResponseEntity<byte[]> entity = template.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
        HttpHeaders headers = entity.getHeaders();
        List<String> conentTypes = headers.get("Content-Type");
        StringBuilder sb = new StringBuilder();
        conentTypes.stream().forEach(contentType -> sb.append(contentType));
        Assert.isTrue(sb.toString().contains("image/jpeg"), "二维码生成失败");

        File file = new File("", StrUtil.format("{}_{}.jpg", id, name));
        FileUtil.writeBytes(entity.getBody(), file);
        log.info("<---结束生成二维码--->");
        return file;
    }

    // 获取表格数据
    @Override
    public Workbook getSheets(String id, List<Map<String, String>> errorMsglist, String groupId, SessionFactory factory) {
        List<TGParams> tgParams = factory.getMapper(TypeParamsMapper.class).queryByGroupId(groupId);
        tgParams.stream().forEach(f -> {
            f.setParamName(CommonUtils.englishtoCamelCase(f.getParamName()));// 英文参数转驼峰
        });
        List<ExportExcelMsg> toplist = new ExportExcelMsg().initExport();
        for (TGParams tgParam : tgParams) {
            boolean exist = toplist.stream().anyMatch(t -> t.getName().equals(tgParam.getParamName()));
            // 存在就跳过
            if (exist) {
                continue;
            }

            if (tgParam.getParamName().equals("安装位置")) {
                toplist.add(new ExportExcelMsg("安装位置名称", 20.0, tgParam.getSort() + 6));
                toplist.add(new ExportExcelMsg("安装位置完整路径", 20.0, tgParam.getSort() + 6));
                continue;
            }
            toplist.add(new ExportExcelMsg(tgParam.getParamName(), 20.0, tgParam.getSort() + 6));
        }
        List<ExcelExportEntity> extracted = new ArrayList<>();
        List<ExportExcelMsg> topSortlist = toplist.stream().sorted(Comparator.comparingInt(ExportExcelMsg::getSort)).collect(Collectors.toList());
        for (ExportExcelMsg exportExcelMsg : topSortlist) {
            extracted.add(new ExcelExportEntity(exportExcelMsg.getName(), exportExcelMsg.getName(), 10));
        }

        // 规范提示
        Map<String, String> standarMsg = new LinkedHashMap<>(10);
        EqExportOrImpUtils.editStandarMsg(tgParams, standarMsg);

        //数据拼装
        List<Map<String, String>> list = new ArrayList<>();
        if (CollUtil.isNotEmpty(errorMsglist)) {
            // 错误信息列
            List<ExcelExportEntity> excelExportEntities = CollUtil.newArrayList(new ExcelExportEntity(ParamimpController.errorMsgStr, ParamimpController.errorMsgStr, 10));
            extracted = CollUtil.unionAll(excelExportEntities, extracted);
            errorMsglist.remove(0);
            list = this.errordynamicListDataByKey(factory, errorMsglist, standarMsg);
        } else{
            list = this.dynamicListDataByKey(factory, id, standarMsg);
        }
        final Workbook workbooktemp = ExcelExportUtil.exportExcel(new ExportParams(), extracted, list);
        return workbooktemp;
    }

    public final static int MAXQTY = 50000;

    /**
     * 填充导出参数数据
     * @param factory
     * @param id
     * @return
     */
    private List<Map<String, String>> dynamicListDataByKey(SessionFactory factory, String id, Map<String, String> standarMsg) {

        // 参数类型
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        int qty = mapper.queryParamEqCount(id);
        cn.hutool.core.lang.Assert.isFalse(qty > MAXQTY, "请缩小导出范围");
        List<ExportParamMsgBean> exportParamMsglist = mapper.queryParamEq(id);  //关键查询
        exportParamMsglist.stream().forEach(e -> {
            e.setParamName(CommonUtils.englishtoCamelCase(e.getParamName()));
        });
        // 所有位置
        List<EquipmentLocation> location = factory.getMapper(EquipmentLocationMapper.class).queryAll();
        // 位置id - 位置全路径
        Map<String, String> locationmap = location.stream().collect(Collectors.toMap(EquipmentLocation::getId, EquipmentLocation::getFullPathName));
        Map<String, List<ExportParamMsgBean>> eqParammap = exportParamMsglist.stream().collect(Collectors.groupingBy(ExportParamMsgBean::getId));
        List<String> eqlist = exportParamMsglist.stream().map(ExportParamMsgBean::getId).distinct().collect(Collectors.toList());
        final int platformNum = eqlist.size();

        if(false) {
            return new ArrayList<>();
        }

        //最终的数据
        List<Map<String, String>> datas = new ArrayList<>();

        // 表头下第一行放置 填报标准
        datas.add(standarMsg);

        for (int i = 0; i < platformNum; i++) {
            String eqid = eqlist.get(i);
            List<ExportParamMsgBean> paramslist = eqParammap.get(eqid);
            Set<String> paramkey = paramslist.stream().map(ExportParamMsgBean::getParamName).collect(Collectors.toSet());

            Map<String, String> hashMap = new LinkedHashMap<>(10);
            hashMap.put("顶层节点", paramslist.get(0).getAncestors());
            hashMap.put("设备id", paramslist.get(0).getId());
            hashMap.put("设备编号", paramslist.get(0).getAmdCode());
            hashMap.put("设备名称", paramslist.get(0).getName());
            hashMap.put("设备分类编码", paramslist.get(0).getTypeCode());
            hashMap.put("设备分类名称", paramslist.get(0).getTypeName());
            hashMap.put("设备路径", paramslist.get(0).getFullPathName());

            for (String paramName : paramkey) {
                if (StrUtil.isBlank(paramName)) {
                    continue;
                }
                for (ExportParamMsgBean exportParamMsgBean : paramslist) {
                    if (StrUtil.isBlank(exportParamMsgBean.getParamName())) {
                        continue;
                    }
                    if (paramName.equals(exportParamMsgBean.getParamName())) {
                        hashMap.put(paramName, exportParamMsgBean.getParamValue());
                        if (paramName.equals("安装位置")) {
//                            hashMap.put(paramName, exportParamMsgBean.getParamResult());
                            hashMap.put("安装位置名称", exportParamMsgBean.getParamValue());
                            hashMap.put("安装位置完整路径", locationmap.get(exportParamMsgBean.getParamResult()));
                        }
                    }
                }
            }
            datas.add(hashMap);

        }
        return datas;
    }


    /**
     * 填充 错误信息 导出参数数据
     * @param factory
     * @param errorMsglist
     * @return
     */
    private List<Map<String, String>> errordynamicListDataByKey(SessionFactory factory, List<Map<String, String>> errorMsglist, Map<String, String> standarMsg) {

        if (CollUtil.isEmpty(errorMsglist)) {
            return new ArrayList<>();
        }
        //最终的数据
        List<Map<String, String>> datas = new ArrayList<>();
        // 表头下第一行放置 填报标准
        datas.add(standarMsg);
        datas = CollUtil.unionAll(datas, errorMsglist);
        return datas;
    }

    /**
     * 获取导入的设备、设备参数、所有位置信息
     * @param impEqId
     * @param factory
     * @return
     */
    public EqComposeBo getEqComposeBo(List<String> impEqId, SessionFactory factory) {
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        // 设备
        List<Equipment> eqlisttemp = mapper.queryByIdIn(impEqId);
        // 设备id-设备类型id map  (虚拟节点，设备类型为空，跳过)
        Map<String, String> eqidTypeIdtemp = eqlisttemp.stream().filter(e->StrUtil.isNotBlank(e.getTypeId())).collect(Collectors.toMap(Equipment::getId, Equipment::getTypeId));
        // 设备参数
        List<EquipmentParams> equipmentParams = mapper.queryByEquipmentIdIn(impEqId);

        // 所有位置信息
        List<EquipmentLocation> locationBeans = factory.getMapper(EquipmentLocationMapper.class).queryAll();
        return new EqComposeBo(eqlisttemp, eqidTypeIdtemp, equipmentParams, locationBeans);
    }


    /**
     * 获取系统 品牌 、人员、组织
     * @param factory
     * @return
     */
    public BaseImpData getBaseImpData(SessionFactory factory) {
        TypeParamsMapper mapper = factory.getMapper(TypeParamsMapper.class);
        // 品牌
        List<BrandStock> brandlist = mapper.queryBrandStocl();
        Map<String, String> brandmap = brandlist.stream().collect(Collectors.toMap(BrandStock::getName, BrandStock::getId, (b1, b2) -> b1));

        // 组织
        List<OrgBean> orgList = mapper.queryAllOrg();
        Map<String, String> orgmap = orgList.stream().collect(Collectors.toMap(OrgBean::getName, OrgBean::getId, (b1, b2) -> b1));

        // 人员
        List<AppUserPo> userlist = mapper.queryAllUser();
        Map<String, String> usermap = userlist.stream().collect(Collectors.toMap(AppUserPo::getName, AppUserPo::getId, (b1, b2) -> b1));
        Map<String, String> userAccNamemap = userlist.stream().collect(Collectors.toMap(AppUserPo::getAccount, AppUserPo::getName, (b1, b2) -> b1));

        BaseImpData baseImpData = new BaseImpData();
        baseImpData.setBrandmap(brandmap);
        baseImpData.setOrgmap(orgmap);
        baseImpData.setUsermap(usermap);
        baseImpData.setUserAccNamemap(userAccNamemap);
        return baseImpData;
    }

    // 匹配 设备分类 对应的 参数集
    public List<TypeParamCompose> getTypeParamComposes(SessionFactory factory) {
        // 设备分类
        List<Type> typelist = factory.getMapper(TypeParamsMapper.class).queryAllType();

        // 基础参数
        List<TGParams> tgplist = factory.getMapper(TypeParamsMapper.class).queryAll();
        tgplist.stream().forEach(f -> {
            f.setParamName(CommonUtils.englishtoCamelCase(f.getParamName()));
        });

        // 技术参数
        List<TypeParamsJs> tpjslist = factory.getMapper(TypeParamsMapper.class).queryAllJs();

        // 基本参数组
        Map<String, List<Select>> tgpIdSelectlist = tgplist.stream()
                .filter(t -> t.getEnterType().equals("radio"))
                .collect(Collectors.toMap(TGParams::getId, new Function<TGParams, List<Select>>() {
                    @Override
                    public List<Select> apply(TGParams tyg) {
                        cn.hutool.core.lang.Assert.isFalse(StrUtil.isBlank(tyg.getDataText()), "参数没有选项");
                        return FastJsonUtils.getJsonToList(tyg.getDataText(), Select.class);
                    }
                }));

        // 技术参数组合
        Map<String, List<Select>> tpjsSelectlist = tpjslist.stream()
                .filter(t -> t.getEnterType().equals("radio"))
                .collect(Collectors.toMap(TypeParamsJs::getId, new Function<TypeParamsJs, List<Select>>() {
                    @Override
                    public List<Select> apply(TypeParamsJs tyg) {
                        cn.hutool.core.lang.Assert.isFalse(StrUtil.isBlank(tyg.getDataText()), tyg.getParamName() + "参数没有选项");
                        return FastJsonUtils.getJsonToList(tyg.getDataText(), Select.class);
                    }
                }));

        List<TypeParamCompose> baseparamlist = new ArrayList();
        for (Type type : typelist) {
            TypeParamCompose typeParamCompose = new TypeParamCompose();
            BeanUtil.copyProperties(type, typeParamCompose);

            // 配置分类 对应的 基础参数集合
            List<TGParams> params = tgplist.stream()
                    .filter(tg -> StrUtil.isNotBlank(tg.getGroupId()) && tg.getGroupId().equals(type.getGroupId()))
                    .collect(Collectors.toList());
            // 遍历基础参数
            for (TGParams param : params) {
                param.setParamlist(tgpIdSelectlist.get(param.getId()));
            }
            typeParamCompose.setTgplist(params);

            // 配置分类 对应的 技术参数 集合
            List<TypeParamsJs> jsparams = tpjslist.stream().filter(tg -> tg.getTypeId().equals(type.getId())).collect(Collectors.toList());
            // 遍历 技术参数
            for (TypeParamsJs param : jsparams) {
                param.setParamlist(tpjsSelectlist.get(param.getId()));
            }
            typeParamCompose.setTpjslist(jsparams);

            baseparamlist.add(typeParamCompose);
        }
        return baseparamlist;
    }


    /**
     * 批量保存设备参数
     * @param updatelist
     * @param insertlist
     * @param factory
     */
    public void batchSaveEquipemntParams(List<EquipmentParams> updatelist, List<EquipmentParams> insertlist, SessionFactory factory) {
        TypeParamsMapper mapper = factory.getMapper(TypeParamsMapper.class);
        if (CollUtil.isNotEmpty(updatelist)) {
            Lists.partition(updatelist, 300).stream().forEach(p -> {
                mapper.updateBatch(p);
            });
        }
        if (CollUtil.isNotEmpty(insertlist)) {
            Lists.partition(insertlist, 300).stream().forEach(p -> {
                mapper.batchInsert(p);
            });
        }
    }

    @Override
    @TaskAnnotation("queryEqlist")
    public PageInfo<Equipment> queryEqlist(SessionFactory factory, PageQuery pageQuery, EqParamQuery query) {

        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        List<Equipment> list = mapper.queryEqlist(query);

        return PageInfo.of(list);
    }

    @Override
    @TaskAnnotation("getByERCode")
    public Equipment getByERCode(SessionFactory factory, ERcodeQuery eRcodeQuery){
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        Assert.isTrue(!StringUtils.isAllEmpty(eRcodeQuery.getKks(), eRcodeQuery.getCode()), "无效的二维码");
        Equipment equipment = null;
        equipment = mapper.getByErCode(eRcodeQuery);
        Assert.notNull(equipment, "设备不存在");
        equipment.setDeptName(orgCacheUtils.getOrgNameById(equipment.getDeptId()));
        // 获取参数列表
        List<EquipmentParams> basicParams = ADOConnection.runTask(typeParamsService, "getBasicParamsByTypeId", List.class, equipment.getTypeId());
        equipment.setBasicParams(basicParams);
        List<EquipmentParams> techParams = ADOConnection.runTask(typeParamsService, "getTechParamsByTypeId", List.class, equipment.getTypeId());
        equipment.setTechParams(techParams);
        Collection<EquipmentParams> params = CollectionUtils.union(equipment.getBasicParams(), equipment.getTechParams());
        List<Map<String, String>> valueMap = mapper.getParams(equipment.getId());
        // 设置参数值
        params.forEach(item -> {
            valueMap.forEach(item1 -> {
                if (item1.get("paramId").equals(item.getParamId())) {
                    item.setParamValue(item1.get("paramValue"));
                    item.setParamResult(item1.get("paramResult"));
                }
            });
        });
        return equipment;

    }

    @Override
    @TaskAnnotation("searchParamsByName")
    public List<EquipmentParams> searchParamsByName(SessionFactory factory, String paramName, String paramType) {
        TypeParamsMapper mapper = factory.getMapper(TypeParamsMapper.class);
        List<EquipmentParams> equipmentParams = mapper.searchParamsByName(paramName, paramType);
        return equipmentParams;
    }

    @Override
    @TaskAnnotation("advancedEquipmentQuery")
    public PageInfo<EquipmentPo> advancedEquipmentQuery(SessionFactory factory, PageQuery pageQuery, AdvancedQuery query) {

        PageHelper.startPage(pageQuery.getPage(), pageQuery.getPageSize(), pageQuery.getOrderBy());
        EquipmentMapper equipmentMapper = factory.getMapper(EquipmentMapper.class);
        query.setLanguage(httpServletRequest.getHeader("Language"));
        List<EquipmentPo> list = equipmentMapper.advancedEquipmentQuery(query);
        return new PageInfo<>(list);
    }

    @Override
    @TaskAnnotation("getEquipmentByParentId")
    public Response getEquipmentByParentId(SessionFactory factory, EquipmentQuery query) {
        String language = httpServletRequest.getHeader("Language");
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        if (StringUtils.isEmpty(query.getParentId())) {
            query.setParentId(rootId);
        }
        // 查询出当前父类设备
        Equipment parentEquipment = mapper.getById(query.getParentId(),language);
        Assert.notNull(parentEquipment,"当前设备不存在");
        EquipmentCodeVO equipmentCodeVO = new EquipmentCodeVO();
        equipmentCodeVO.setId(parentEquipment.getId());
        equipmentCodeVO.setCode(parentEquipment.getCode());
        equipmentCodeVO.setEncode(parentEquipment.getEncode());
        equipmentCodeVO.setName(parentEquipment.getName());
        equipmentCodeVO.setIsVirtual(parentEquipment.getIsVirtual());
        List<EquipmentCodeVO> list = new ArrayList<>();
        list.add(equipmentCodeVO);

        // 查询出子类设备
        List<EquipmentCodeVO> childEquipments = mapper.getEquipmentByParentId(Arrays.asList(query.getParentId()));

        if (CollectionUtils.isNotEmpty(childEquipments)){
            List<String> ids = childEquipments.stream().map(EquipmentCodeVO::getId).collect(Collectors.toList());
            recursiveQuery(factory, ids, childEquipments);
        }

        list.addAll(childEquipments);
        // 过滤出虚拟节点
        list = list.stream().filter(e->"0".equals(e.getIsVirtual())).collect(Collectors.toList());
        return Response.success(list);
    }

    public List<EquipmentCodeVO> recursiveQuery(SessionFactory factory, List<String> ids, List<EquipmentCodeVO> childEquipments){
        EquipmentMapper mapper = factory.getMapper(EquipmentMapper.class);
        //
        int batchSize = 50;
        List<List<String>> batchIds = batch(ids, batchSize);
        for (List<String> batchId : batchIds) {
            List<EquipmentCodeVO> equipment = mapper.getEquipmentByParentId(batchId);
            childEquipments.addAll(equipment);
            if (CollectionUtils.isNotEmpty(equipment)){
              return recursiveQuery(factory,equipment.stream().map(EquipmentCodeVO::getId).collect(Collectors.toList()), childEquipments);
            }
        }
        return childEquipments;
    }


    public  <T> List<List<T>> batch(List<T> list, int batchSize) {
        int totalSize = list.size();
        return IntStream.iterate(0, i -> i + batchSize)
                // 向上取整的思想
                .limit((totalSize + batchSize - 1) / batchSize)
                .mapToObj(start -> list.stream().skip(start).limit(batchSize).collect(Collectors.toList()))
                .collect(Collectors.toList());
    }

    //生成KKS编码
    public String getKKS(EquipmentMapper mapper,Equipment equipment,Equipment boot,String equipmentCode,String LanguageType){
        Equipment parent = mapper.getById(equipment.getParentId(),LanguageType);
        //新增设备
        if (FloorEnum.LEVEL5.getValue().equals(boot.getFloor())){
            if (FloorEnum.LEVEL5.getValue().equals(parent.getFloor())){
                getKKS(mapper,parent,boot,equipmentCode,LanguageType);
            }if (FloorEnum.LEVEL4.getValue().equals(parent.getFloor())){
                Integer maxEquipmentCodeByKKS = mapper.getMaxEquipmentCodeByKKS(parent.getEncode() + equipmentCode);
                if (maxEquipmentCodeByKKS==null){
                    maxEquipmentCodeByKKS=0;
                }
                return parent.getEncode()+equipmentCode+(String.format("%03d", Integer.valueOf(maxEquipmentCodeByKKS) + 1));
            }
            else {
                //无法生成kks
                return "";
            }
        }//新增部件
        else if (FloorEnum.LEVEL6.getValue().equals(boot.getFloor())){
            if (FloorEnum.LEVEL5.getValue().equals(parent.getFloor())){
                Integer maxEquipmentCodeByKKS = mapper.getMaxEquipmentCodeByKKS(parent.getEncode() + equipmentCode);
                if (maxEquipmentCodeByKKS==null){
                    maxEquipmentCodeByKKS=0;
                }
                return parent.getEncode()+equipmentCode+(String.format("%02d", Integer.valueOf(maxEquipmentCodeByKKS) + 1));
            }if (FloorEnum.LEVEL6.getValue().equals(parent.getFloor())){
                getKKS(mapper,parent,boot,equipmentCode,LanguageType);
            }
            else {
                //无法生成kks
                return "";
            }
        }
        return "";
    }

}
